﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.IO;
using Org.BouncyCastle.X509;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;

namespace SealManagement.Common
{
    public class SMToolClass
    {
        public static readonly byte[] userId = Encoding.ASCII.GetBytes("1234567812345678");
        public static readonly BigInteger ecc_a = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16);
        public static readonly BigInteger ecc_b = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16);
        public static readonly BigInteger ecc_gx = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
        public static readonly BigInteger ecc_gy = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
        public static readonly BigInteger ecc_n = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16);
        public static readonly BigInteger ecc_p = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16);
        public static readonly ECCurve ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b);
        public static readonly ECPoint ecc_point_g =
            new FpPoint(ecc_curve, ecc_curve.FromBigInteger(ecc_gx), ecc_curve.FromBigInteger(ecc_gy));
        public static readonly ECDomainParameters ecc_bc_spec = new ECDomainParameters(ecc_curve, ecc_point_g, ecc_n);

        private static bool TestSignVerify(AsymmetricCipherKeyPair key)
        {
            byte[] sig = Sm2Sign(new byte[] { 0x01, 0x02, 0x03, 0x04 }, key);
            bool ret = Verify(new byte[] { 0x01, 0x02, 0x03, 0x04 }, sig,
                ((ECPublicKeyParameters)key.Public).Q);
            var x = To32Bytes(((ECPublicKeyParameters)key.Public).Q.Normalize().XCoord.ToBigInteger());
            var y = To32Bytes(((ECPublicKeyParameters)key.Public).Q.Normalize().YCoord.ToBigInteger());
            return ret = Verify(new byte[] { 0x01, 0x02, 0x03, 0x04 }, sig, x, y);
        }

        public static byte[] GetZ(ECPoint ecPoint)
        {
            List<byte> preData = new List<byte>();
            preData.AddRange(BitConverter.GetBytes((short)(userId.Length * 8)).Reverse());
            preData.AddRange(userId);
            preData.AddRange(To32Bytes(ecc_a));
            preData.AddRange(To32Bytes(ecc_b));
            preData.AddRange(To32Bytes(ecc_gx));
            preData.AddRange(To32Bytes(ecc_gy));
            preData.AddRange(To32Bytes(ecPoint.Normalize().XCoord.ToBigInteger()));
            preData.AddRange(To32Bytes(ecPoint.Normalize().YCoord.ToBigInteger()));
            SM3Digest sm3 = new SM3Digest();
            sm3.BlockUpdate(preData.ToArray(), 0, preData.ToArray().Length);
            byte[] hashData = new byte[32];
            sm3.DoFinal(hashData, 0);
            return hashData;
        }

        public static byte[] GetSM3(byte[] msg, byte[] certBytes)
        {
            X509Certificate2 x5092 = new X509Certificate2(certBytes);
            byte[] publicKey = x5092.GetPublicKey();

            publicKey = publicKey.Skip(1).Take(64).ToArray();

            byte[] publicKeyX = publicKey.Skip(publicKey.Length - 32 - 32).Take(32).ToArray();
            byte[] publickKeyY = publicKey.Skip(publicKey.Length - 32).Take(32).ToArray();
            return GetSM3(msg, publicKeyX, publickKeyY);
        }

        public static byte[] GetSM3(byte[] msg, byte[] publicKeyX, byte[] publicKeyY)
        {
            //String strcertPKX = BitConverter.ToString(publicKeyX).Replace("-", "");
            //String strcertPKY = BitConverter.ToString(publicKeyY).Replace("-", "");
            //BigInteger biX = new BigInteger(strcertPKX, 16);
            //BigInteger biY = new BigInteger(strcertPKY, 16);

            //ECFieldElement x = new FpFieldElement(ecc_p, biX);
            //ECFieldElement y = new FpFieldElement(ecc_p, biY);
            //ECPoint userKey = new FpPoint(ecc_curve, x, y);

            ECPoint userKey = ecc_curve.ValidatePoint(new BigInteger(1, publicKeyX),
                new BigInteger(1, publicKeyY));

            SM3Digest sm3 = new SM3Digest();
            byte[] z = GetZ(userKey);
            sm3.BlockUpdate(z, 0, z.Length);


            byte[] p = msg;
            sm3.BlockUpdate(p, 0, p.Length);

            byte[] md = new byte[32];
            sm3.DoFinal(md, 0);
            return md;
        }

        public static byte[] Sm2Sign(byte[] msg, byte[] privateBytes, byte[] certBytes)
        {
            X509Certificate2 x5092 = new X509Certificate2(certBytes);
            byte[] publicKey = x5092.GetPublicKey();

            publicKey = publicKey.Skip(1).Take(64).ToArray();

            byte[] publicKeyX = publicKey.Skip(publicKey.Length - 32 - 32).Take(32).ToArray();
            byte[] publickKeyY = publicKey.Skip(publicKey.Length - 32).Take(32).ToArray();
            return Sm2Sign(msg, privateBytes, publicKeyX, publickKeyY);
        }


        public static byte[] Sm2Sign(byte[] msg, byte[] privateBytes, byte[] publicKeyX, byte[] publicKeyY)
        {
            //string pubKeyXStr = BitConverter.ToString(publicKeyX).Replace("-", "");
            //string pubKeyYStr = BitConverter.ToString(publickKeyY).Replace("-", "");
            //string privateStr = BitConverter.ToString(privateBytes).Replace("-", "");
            //BigInteger biX = new BigInteger(pubKeyXStr, 16);
            //BigInteger biY = new BigInteger(pubKeyYStr, 16);
            //BigInteger biPri = new BigInteger(privateStr, 16);

            //ECFieldElement x = new FpFieldElement(ecc_p, biX);
            //ECFieldElement y = new FpFieldElement(ecc_p, biY);
            //ECPoint userKey = new FpPoint(ecc_curve, x, y);

            ECPoint userKey = ecc_curve.ValidatePoint(new BigInteger(1, publicKeyX),
                new BigInteger(1, publicKeyY));
            BigInteger biPri = new BigInteger(1, privateBytes);

            SM3Digest sm3 = new SM3Digest();
            byte[] z = GetZ(userKey);
            sm3.BlockUpdate(z, 0, z.Length);

            byte[] p = msg;
            sm3.BlockUpdate(p, 0, p.Length);

            byte[] hashData = new byte[32];
            sm3.DoFinal(hashData, 0);

            // e  
            BigInteger e = new BigInteger(1, hashData);
            // k  
            BigInteger k = null;
            ECPoint kp = null;
            BigInteger r = null;
            BigInteger s = null;
            BigInteger userD = null;

            do
            {
                do
                {
                    k = biPri;
                    kp = userKey;

                    userD = biPri;

                    // r  
                    r = e.Add(kp.Normalize().XCoord.ToBigInteger());
                    r = r.Mod(ecc_n);
                }
                while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));

                // (1 + dA)~-1  
                BigInteger da_1 = userD.Add(BigInteger.One);
                da_1 = da_1.ModInverse(ecc_n);
                // s  
                s = r.Multiply(userD);
                s = k.Subtract(s).Mod(ecc_n);
                s = da_1.Multiply(s).Mod(ecc_n);
            }
            while (s.Equals(BigInteger.Zero));
            return To32Bytes(r).Concat(To32Bytes(s)).ToArray();
        }

        public static byte[] Sm2Sign(byte[] msg, AsymmetricCipherKeyPair keypair)
        {
            ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public;
            ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private;
            var x = To32Bytes(ecpub.Q.Normalize().XCoord.ToBigInteger());
            var y = To32Bytes(ecpub.Q.Normalize().YCoord.ToBigInteger());
            var pri = To32Bytes(ecpriv.D);
            return Sm2Sign(msg, pri, x, y);

            /*
            SM3Digest sm3 = new SM3Digest();

            ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public;

            byte[] z = GetZ(ecpub.Q);
            sm3.BlockUpdate(z, 0, z.Length);

            byte[] p = msg;
            sm3.BlockUpdate(p, 0, p.Length);

            byte[] hashData = new byte[32];
            sm3.DoFinal(hashData, 0);

            // e  
            BigInteger e = new BigInteger(1, hashData);
            // k  
            BigInteger k = null;
            ECPoint kp = null;
            BigInteger r = null;
            BigInteger s = null;
            BigInteger userD = null;

            do
            {
                do
                {

                    ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private;
                    k = ecpriv.D;
                    kp = ecpub.Q;

                    userD = ecpriv.D;

                    // r  
                    r = e.Add(kp.Normalize().XCoord.ToBigInteger());
                    r = r.Mod(ecc_n);
                }
                while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n));

                // (1 + dA)~-1  
                BigInteger da_1 = userD.Add(BigInteger.One);
                da_1 = da_1.ModInverse(ecc_n);
                // s  
                s = r.Multiply(userD);
                s = k.Subtract(s).Mod(ecc_n);
                s = da_1.Multiply(s).Mod(ecc_n);
            }
            while (s.Equals(BigInteger.Zero));

            //byte[] btRS = new byte[64];
            //List<byte> btR = r.ToByteArray().ToList();
            //List<byte> btS = s.ToByteArray().ToList();
            //if (btR.Count == 33)
            //{
            //    btR.RemoveAt(0);
            //}
            //if (btS.Count == 33)
            //{
            //    btS.RemoveAt(0);
            //}
            //return btR.Concat(btS).ToArray();
            return To32Bytes(r).Concat(To32Bytes(s)).ToArray();
            */
        }

        public static bool Verify(byte[] msg, byte[] signData, ECPoint publicKey)
        {
            //var x = publicKey.Normalize().XCoord.ToBigInteger().ToByteArray();
            //var y = publicKey.Normalize().YCoord.ToBigInteger().ToByteArray();
            //if (x.Length == 33)
            //{
            //    x = x.Skip(1).ToArray();
            //}
            //if (y.Length == 33)
            //{
            //    y = y.Skip(1).ToArray();
            //}
            var x = To32Bytes(publicKey.Normalize().XCoord.ToBigInteger());
            var y = To32Bytes(publicKey.Normalize().YCoord.ToBigInteger());
            return Verify(msg, signData, x, y);
        }

        public static bool Verify(byte[] msg, byte[] signData, byte[] certBytes)
        {
            X509Certificate2 x5092 = new X509Certificate2(certBytes);
            byte[] publicKey = x5092.GetPublicKey();

            publicKey = publicKey.Skip(1).Take(64).ToArray();

            byte[] publicKeyX = publicKey.Skip(publicKey.Length - 32 - 32).Take(32).ToArray();
            byte[] publickKeyY = publicKey.Skip(publicKey.Length - 32).Take(32).ToArray();

            return Verify(msg, signData, publicKeyX, publickKeyY);
        }



        public static bool Verify(byte[] msg, byte[] signData, byte[] publicKeyX, byte[] publickKeyY)
        {
            ECPoint userKey = ecc_curve.ValidatePoint(new BigInteger(1, publicKeyX),
                new BigInteger(1, publickKeyY));


            SM3Digest sm3 = new SM3Digest();
            byte[] z = GetZ(userKey);
            sm3.BlockUpdate(z, 0, z.Length);


            byte[] p = msg;
            sm3.BlockUpdate(p, 0, p.Length);

            byte[] md = new byte[32];
            sm3.DoFinal(md, 0);

            return VerifySM3(md, signData, publicKeyX, publickKeyY);
        }

        public static bool VerifySM3(byte[] sm3Bytes, byte[] signData, ECPoint publicKey)
        {
            var x = To32Bytes(publicKey.Normalize().XCoord.ToBigInteger());
            var y = To32Bytes(publicKey.Normalize().YCoord.ToBigInteger());
            return VerifySM3(sm3Bytes, signData, x, y);
        }
        public static bool VerifySM3(byte[] sm3Bytes, byte[] signData, byte[] certBytes)
        {
            X509Certificate2 x5092 = new X509Certificate2(certBytes);
            byte[] publicKey = x5092.GetPublicKey();

            publicKey = publicKey.Skip(1).Take(64).ToArray();

            byte[] publicKeyX = publicKey.Skip(publicKey.Length - 32 - 32).Take(32).ToArray();
            byte[] publickKeyY = publicKey.Skip(publicKey.Length - 32).Take(32).ToArray();
            return VerifySM3(sm3Bytes, signData, publicKeyX, publickKeyY);
        }
        public static bool VerifySM3(byte[] sm3Bytes, byte[] signData, byte[] publicKeyX, byte[] publickKeyY)
        {
            ECPoint userKey = ecc_curve.ValidatePoint(new BigInteger(1, publicKeyX),
                new BigInteger(1, publickKeyY));

            if (signData.Length == 128)
            {
                signData = signData.Skip(32).Take(32).Concat(signData.Skip(32 * 3).Take(32)).ToArray();
            }

            byte[] btR = signData.Take(32).ToArray();
            byte[] btS = signData.Skip(32).Take(32).ToArray();

            BigInteger r = new BigInteger(1, btR);
            BigInteger s = new BigInteger(1, btS);

            BigInteger e = new BigInteger(1, sm3Bytes);
            BigInteger t = r.Add(s).Mod(ecc_n);

            if (t.Equals(BigInteger.Zero))
                return false;


            // x1y1  
            ECPoint x1y1 = ecc_point_g.Multiply(s);
            x1y1 = x1y1.Add(userKey.Multiply(t));

            // R  
            BigInteger R = e.Add(x1y1.Normalize().XCoord.ToBigInteger()).Mod(ecc_n);

            return r.Equals(R);
        }

        public static byte[] Encrypt(byte[] publicKey, byte[] data)
        {
            if (publicKey == null || publicKey.Length == 0)
            {
                return null;
            }

            if (data == null || data.Length == 0)
            {
                return null;
            }

            byte[] source = new byte[data.Length];
            Array.Copy(data, 0, source, 0, data.Length);

            SM2Cipher sm2Cipher = new SM2Cipher();
            ECPoint userKey = ecc_curve.DecodePoint(publicKey);

            ECPoint c1 = sm2Cipher.Init_enc(userKey);
            sm2Cipher.Encrypt(source);
            byte[] c3 = new byte[32];
            sm2Cipher.Dofinal(c3);


            //C1 || C3 || C2拼装成加密字串
            return c1.GetEncoded().Skip(1).Concat(c3).Concat(source).ToArray();

        }

        public static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)
        {
            if (privateKey == null || privateKey.Length == 0)
            {
                return null;
            }

            if (encryptedData == null || encryptedData.Length == 0)
            {
                return null;
            }
            //密文结构：C1 || C3 || C2
            byte[] c1Bytes = encryptedData.Take(64).ToArray();
            byte[] c3Bytes = encryptedData.Skip(c1Bytes.Length).Take(32).ToArray();
            byte[] c2Bytes = encryptedData.Skip(c1Bytes.Length + c3Bytes.Length).ToArray();

            //SM2 sm2 = SM2.Instance();
            BigInteger userD = new BigInteger(1, privateKey);

            //通过C1实体字节来生成ECPoint
            ECPoint c1 = ecc_curve.ValidatePoint(new BigInteger(1, c1Bytes.Take(32).ToArray()),
                new BigInteger(1, c1Bytes.Skip(32).Take(32).ToArray()));
            SM2Cipher sm2Cipher = new SM2Cipher();
            sm2Cipher.Init_dec(userD, c1);
            sm2Cipher.Decrypt(c2Bytes);
            sm2Cipher.Dofinal(c3Bytes);

            //返回解密结果
            return c2Bytes;
        }

        /// <summary>
        /// 创建数字信封
        /// </summary>
        /// <param name="x509Certificate2Collection">接收者的证书集合</param>
        /// <param name="contentBytes">要加密的数据</param>
        /// <param name="encryptionOid">默认AES128,可传入CmsEnvelopedGenerator.XXXX枚举</param>
        public static byte[] CreateEnvelopedData(X509Certificate2Collection x509Certificate2Collection, byte[] contentBytes,
            string encryptionOid = "2.16.840.1.101.3.4.1.2")
        {
            SM2CmsEnvelopedDataGenerator sm2CmsEnvelopedDataGenerator =
                new SM2CmsEnvelopedDataGenerator(new SecureRandom(),
                    x509Certificate2Collection);
            CmsProcessable content = new CmsProcessableByteArray(contentBytes);
            var data = sm2CmsEnvelopedDataGenerator
                .GenerateSM2CmsEnvelopedData(content, CmsEnvelopedGenerator.Aes128Cbc)
                .GetEncoded();
            return data;
        }

        /// <summary>
        /// 解析数字信封
        /// </summary>
        /// <param name="cert"></param>
        /// <param name="privateKeyBytes"></param>
        /// <param name="envelopedDataBytes"></param>
        /// <returns></returns>
        public static byte[] UnpackEnvelopedData(X509Certificate2 cert, byte[] privateKeyBytes, byte[] envelopedDataBytes)
        {
            CmsEnvelopedData cmsEnvelopedData = new CmsEnvelopedData(envelopedDataBytes);
            var envelopedData = EnvelopedData.GetInstance(cmsEnvelopedData.ContentInfo.Content);
            foreach (var each in envelopedData.RecipientInfos.ToArray())
            {
                var eachRecipientInfo = RecipientInfo.GetInstance(each);
                var keyTransRecipientInfo = KeyTransRecipientInfo.GetInstance(eachRecipientInfo.Info);
                if (IssuerAndSerialNumber.GetInstance(keyTransRecipientInfo.RecipientIdentifier.ID).SerialNumber
                        .ToString() == new X509CertificateParser().ReadCertificate(cert.RawData).SerialNumber.ToString())
                {
                    var encryptedKey = keyTransRecipientInfo.EncryptedKey.GetOctets();
                    var theKey = Decrypt(privateKeyBytes, encryptedKey);
                    var data = GetOriginalData(
                        envelopedData.EncryptedContentInfo.EncryptedContent.GetOctets(),
                        envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm, theKey);
                    return data;
                }
            }
            return null;
        }

        /// <summary>
        /// 解析数字信封
        /// </summary>
        /// <param name="cert"></param>
        /// <param name="envelopedDataBytes"></param>
        /// <param name="decryptFunc">私钥解析函数，参数为被公钥加密的对称密钥，返回值为私钥解密后的对称密钥</param>
        /// <returns></returns>
        public static byte[] UnpackEnvelopedData(X509Certificate2 cert, byte[] envelopedDataBytes, Func<byte[], byte[]> decryptFunc)
        {
            CmsEnvelopedData cmsEnvelopedData = new CmsEnvelopedData(envelopedDataBytes);
            var envelopedData = EnvelopedData.GetInstance(cmsEnvelopedData.ContentInfo.Content);
            foreach (var each in envelopedData.RecipientInfos.ToArray())
            {
                var eachRecipientInfo = RecipientInfo.GetInstance(each);
                var keyTransRecipientInfo = KeyTransRecipientInfo.GetInstance(eachRecipientInfo.Info);
                if (IssuerAndSerialNumber.GetInstance(keyTransRecipientInfo.RecipientIdentifier.ID).SerialNumber
                        .ToString() == new X509CertificateParser().ReadCertificate(cert.RawData).SerialNumber.ToString())
                {
                    var encryptedKey = keyTransRecipientInfo.EncryptedKey.GetOctets();
                    var theKey = decryptFunc(encryptedKey);
                    if (theKey == null)
                    {
                        return null;
                    }
                    var data = GetOriginalData(
                        envelopedData.EncryptedContentInfo.EncryptedContent.GetOctets(),
                        envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm, theKey);
                    return data;
                }
            }
            return null;
        }

        /// <summary>
        /// 从数字信封中取出使用对应证书加密的对称密钥
        /// </summary>
        /// <param name="cert">对应的证书</param>
        /// <param name="envelopedDataBytes">数字信封</param>
        /// <returns></returns>
        public static byte[] GetEncryptedKeyFromEnvelopedData(X509Certificate2 cert, byte[] envelopedDataBytes)
        {
            CmsEnvelopedData cmsEnvelopedData = new CmsEnvelopedData(envelopedDataBytes);
            var envelopedData = EnvelopedData.GetInstance(cmsEnvelopedData.ContentInfo.Content);
            foreach (var each in envelopedData.RecipientInfos.ToArray())
            {
                var eachRecipientInfo = RecipientInfo.GetInstance(each);
                var keyTransRecipientInfo = KeyTransRecipientInfo.GetInstance(eachRecipientInfo.Info);
                if (IssuerAndSerialNumber.GetInstance(keyTransRecipientInfo.RecipientIdentifier.ID).SerialNumber
                        .ToString() == new X509CertificateParser().ReadCertificate(cert.RawData).SerialNumber.ToString())
                {
                    var encryptedKey = keyTransRecipientInfo.EncryptedKey.GetOctets();
                    return encryptedKey;
                }
            }
            return null;
        }

        public static byte[] AddRecipientInfosToEnvelopedData(X509Certificate2Collection x509Certificate2Collection,
            byte[] envelopedDataBytes, byte[] key)
        {
            var generator = new SM2CmsEnvelopedDataGenerator(x509Certificate2Collection);
            CmsEnvelopedData cmsEnvelopedData = new CmsEnvelopedData(envelopedDataBytes);
            var envelopedData = EnvelopedData.GetInstance(cmsEnvelopedData.ContentInfo.Content);
            var newCmsEnvelopedData = generator.AddReceiverToEnvelopedData(envelopedData.EncryptedContentInfo,
                envelopedData.RecipientInfos.ToArray().ToList().Select(s => RecipientInfo.GetInstance(s)).ToList(),
                key);
            return newCmsEnvelopedData.GetEncoded();
        }

        private static byte[] GetOriginalData(byte[] encryptedContent, AlgorithmIdentifier algorithmIdentifier, byte[] key)
        {
            try
            {
                var cipher = CipherUtilities.GetCipher(algorithmIdentifier.Algorithm);
                Asn1Encodable parameters = algorithmIdentifier.Parameters;
                Asn1Object asn1Params = parameters == null ? (Asn1Object)null : parameters.ToAsn1Object();
                var keyParameter = ParameterUtilities.CreateKeyParameter(algorithmIdentifier.Algorithm, key);
                ICipherParameters cipherParameters = (ICipherParameters)keyParameter;
                if (asn1Params != null && !(asn1Params is Asn1Null))
                {
                    cipherParameters = ParameterUtilities.GetCipherParameters(algorithmIdentifier.Algorithm, cipherParameters, asn1Params);
                }
                else
                {
                    string id = algorithmIdentifier.Algorithm.Id;
                    if (id.Equals(CmsEnvelopedGenerator.DesEde3Cbc) || id.Equals("1.3.6.1.4.1.188.7.1.1.2") || id.Equals("1.2.840.113533.7.66.10"))
                        cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
                }
                cipher.Init(false, cipherParameters);
                var stream = (CmsReadable)new CmsProcessableInputStream(
                    new CipherStream(new MemoryStream(encryptedContent), cipher, null));
                var aaa = new CmsTypedStream(stream.GetInputStream());
                var bbb = aaa.ContentStream;
                var data = Streams.ReadAll(bbb);
                return data;

            }
            catch (Exception e)
            {
                return null;
            }
        }

        public static byte[] To32Bytes(BigInteger bigInteger)
        {
            var x = bigInteger.ToByteArray();
            if (x.Length == 33)
            {
                x = x.Skip(1).ToArray();
            }
            else if (x.Length < 32)
            {
                List<byte> temp = new List<byte>(32);
                byte[] zeroBytes = new byte[32 - x.Length];
                temp.AddRange(zeroBytes);
                temp.AddRange(x);
                x = temp.ToArray();
            }
            return x;
        }

        public static void Test()
        {

            //ToolClass.DecodeLicBytes(File.ReadAllBytes("d:\\1.lic"), out byte[] certBytes1, out string xml,
            //    out byte[] picBytes);
            var certBytes = File.ReadAllBytes("d:\\1.cer");
            //X509Certificate2 x5092 = new X509Certificate2(certBytes);
            //byte[] certPK = x5092.GetPublicKey();
            //byte[] data111 = new byte[] { 0x00, 0x01, 0x02, 0x03 };
            //byte[] en = Encrypt(certPK, data111);
            //File.WriteAllBytes("d:\\1.p7m", en);

            X509Certificate2Collection x509Certificate2Collection = new X509Certificate2Collection();
            x509Certificate2Collection.Add(new X509Certificate2(certBytes));
            var envelopedData = File.ReadAllBytes("d:\\1.pdf");
            var key = Convert.FromBase64String("8KcJ2YYzKD1zLxuT+dx1mg==");
            var data = AddRecipientInfosToEnvelopedData(x509Certificate2Collection, envelopedData, key);

            //ECKeyGenerationParameters ecc_ecgenparam = new ECKeyGenerationParameters(ecc_bc_spec, new SecureRandom());
            //ECKeyPairGenerator ecc_key_pair_generator = new ECKeyPairGenerator();
            //ecc_key_pair_generator.Init(ecc_ecgenparam);
            //AsymmetricCipherKeyPair key = ecc_key_pair_generator.GenerateKeyPair();
            //TestSignVerify(key);

            //byte[] data111 = new byte[]{0x00,0x01,0x02,0x03};
            //byte[] en = Encrypt(((ECPublicKeyParameters) key.Public).Q.GetEncoded(), data111);
            //byte[] de = Decrypt(((ECPrivateKeyParameters) key.Private).D.ToByteArray(), en);

            //SM2CmsEnvelopedDataGenerator sm2CmsEnvelopedDataGenerator = new SM2CmsEnvelopedDataGenerator(new SecureRandom(), null);

            //CmsProcessable content = new CmsProcessableByteArray(data111);

            //var attributes = new Hashtable
            //{
            //    [X509Name.E] = "123@1.c",
            //    [X509Name.CN] = "test",
            //    [X509Name.O] = "test",
            //    [X509Name.C] = "Zh"
            //};
            //var ordering = new ArrayList { X509Name.E, X509Name.CN, X509Name.O, X509Name.C };
            //X509Name issuerDN = new X509Name(ordering, attributes);
            //BigInteger serialNumber = BigInteger.ProbablePrime(120, new Random());
            //IssuerAndSerialNumber issuerAndSerialNumber = new IssuerAndSerialNumber(issuerDN, serialNumber);

            //var data = sm2CmsEnvelopedDataGenerator.GenerateSM2CmsEnvelopedData(content, CmsEnvelopedGenerator.Aes128Cbc, key.Public, issuerAndSerialNumber).GetEncoded();
            //File.WriteAllBytes("d:\\1.p7m", data);

            //CmsEnvelopedData cmsEnvelopedData = new CmsEnvelopedData(data);
            //var envelopedData = EnvelopedData.GetInstance(cmsEnvelopedData.ContentInfo.Content);
            //foreach (var each in envelopedData.RecipientInfos.ToArray())
            //{
            //    var eachRecipientInfo = RecipientInfo.GetInstance(each);
            //    var keyTransRecipientInfo = KeyTransRecipientInfo.GetInstance(eachRecipientInfo.Info);
            //    if (IssuerAndSerialNumber.GetInstance(keyTransRecipientInfo.RecipientIdentifier.ID).SerialNumber.ToString() == issuerAndSerialNumber.SerialNumber.ToString())
            //    {
            //        var encryptedKey = keyTransRecipientInfo.EncryptedKey.GetOctets();
            //        var theKey = Decrypt(((ECPrivateKeyParameters)key.Private).D.ToByteArray(), encryptedKey);
            //        var ccc = sm2CmsEnvelopedDataGenerator.GetOriginalData(
            //            envelopedData.EncryptedContentInfo.EncryptedContent.GetOctets(),
            //            envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm, theKey);

            //    }
            //}



        }
    }

    public class SM2CmsEnvelopedDataGenerator : CmsEnvelopedDataGenerator
    {
        private SecureRandom rand;
        public X509Certificate2Collection Certs { get; set; }

        public SM2CmsEnvelopedDataGenerator(X509Certificate2Collection receiverCerts)
        {
            this.Certs = receiverCerts;
        }
        public SM2CmsEnvelopedDataGenerator(SecureRandom rand, X509Certificate2Collection receiverCerts) : base(rand)
        {
            this.rand = rand;
            this.Certs = receiverCerts;
        }

        public RecipientInfo GenerateRecipientInfo(KeyParameter contentEncryptionKey, AsymmetricKeyParameter publicKey,
            IssuerAndSerialNumber issuerAndSerialNumber)
        {
            byte[] key = contentEncryptionKey.GetKey();
            byte[] str = SMToolClass.Encrypt(((ECPublicKeyParameters)publicKey).Q.GetEncoded(), key);
            var recipientInfo = new RecipientInfo(new KeyTransRecipientInfo(
                new RecipientIdentifier(issuerAndSerialNumber),
                new AlgorithmIdentifier(new DerObjectIdentifier("1.2.156.10197.301.3")),
                new DerOctetString(str)));
            var asn1Sequence = Asn1Sequence.GetInstance(recipientInfo);
            Asn1EncodableVector encodableVector = new Asn1EncodableVector();
            encodableVector.Add(new DerInteger(1));
            for (var i = 1; i < asn1Sequence.Count; i++)
            {
                encodableVector.Add(asn1Sequence[i]);
            }
            recipientInfo = RecipientInfo.GetInstance(new DerSequence(encodableVector));
            return recipientInfo;
        }

        public CmsEnvelopedData GenerateSM2CmsEnvelopedData(CmsProcessable content, string encryptionOid)
        {
            List<PublicKeyAndIssuerSerialNumber> publicKeyAndIssuerSerialNumbers = new List<PublicKeyAndIssuerSerialNumber>();
            var parser = new X509CertificateParser();
            foreach (X509Certificate2 cert in Certs)
            {
                X509Certificate certificate = parser.ReadCertificate(cert.RawData);
                publicKeyAndIssuerSerialNumbers.Add(new PublicKeyAndIssuerSerialNumber()
                {
                    PublicKey = certificate.GetPublicKey(),
                    IssuerAndSerialNumber = new IssuerAndSerialNumber(certificate.IssuerDN, certificate.SerialNumber)
                });
            }
            return GenerateSM2CmsEnvelopedData(content, encryptionOid, publicKeyAndIssuerSerialNumbers);

            //CipherKeyGenerator keyGenerator = GeneratorUtilities.GetKeyGenerator(encryptionOid);
            //keyGenerator.Init(new KeyGenerationParameters(this.rand, keyGenerator.DefaultStrength));
            //var keyGen = keyGenerator;
            //KeyParameter keyParameter;
            //AlgorithmIdentifier algorithmIdentifier;
            //Asn1OctetString encryptedContent;
            //try
            //{
            //    byte[] key = keyGen.GenerateKey();
            //    keyParameter = ParameterUtilities.CreateKeyParameter(encryptionOid, key);
            //    Asn1Encodable asn1Parameters = this.GenerateAsn1Parameters(encryptionOid, key);
            //    algorithmIdentifier = this.GetAlgorithmIdentifier(encryptionOid, keyParameter, asn1Parameters, out var cipherParameters);
            //    IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid);
            //    cipher.Init(true, new ParametersWithRandom(cipherParameters, this.rand));
            //    MemoryStream memoryStream = new MemoryStream();
            //    CipherStream cipherStream = new CipherStream(memoryStream, null, cipher);
            //    content.Write(cipherStream);
            //    cipherStream.Close();
            //    encryptedContent = new BerOctetString(memoryStream.ToArray());
            //}
            //catch (Exception ex)
            //{
            //    throw new CmsException("encrypt content failed.", ex);
            //}
            //Asn1EncodableVector v = new Asn1EncodableVector();
            //foreach (X509Certificate2 cert in Certs)
            //{
            //    try
            //    {
            //        v.Add((Asn1Encodable)GenerateRecipientInfo(keyParameter, new X509CertificateParser()
            //            .ReadCertificate(cert.RawData)));
            //    }
            //    catch (Exception ex)
            //    {
            //        throw new CmsException("add RecipientInfo failed", ex);
            //    }
            //}
            //EncryptedContentInfo encryptedContentInfo = new EncryptedContentInfo(CmsObjectIdentifiers.Data, algorithmIdentifier, encryptedContent);
            //Asn1Set unprotectedAttrs = null;
            //if (UnprotectedAttributeGenerator != null)
            //    unprotectedAttrs = new BerSet(UnprotectedAttributeGenerator.GetAttributes(new Hashtable()).ToAsn1EncodableVector());
            //var envelopedData = new EnvelopedData(null, new DerSet(v), encryptedContentInfo,
            //    unprotectedAttrs);
            //var asn1Sequence = Asn1Sequence.GetInstance(envelopedData);
            //Asn1EncodableVector encodableVector = new Asn1EncodableVector();
            //encodableVector.Add(new DerInteger(1));
            //for (var i = 1; i < asn1Sequence.Count; i++)
            //{
            //    encodableVector.Add(asn1Sequence[i]);
            //}
            //var contentInfo = new ContentInfo(CmsObjectIdentifiers.EnvelopedData,
            //    new DerSequence(encodableVector));
            //return new CmsEnvelopedData(contentInfo);
        }

        public CmsEnvelopedData GenerateSM2CmsEnvelopedData(CmsProcessable content, string encryptionOid,
            List<PublicKeyAndIssuerSerialNumber> receiverList)
        {
            CipherKeyGenerator keyGenerator = GeneratorUtilities.GetKeyGenerator(encryptionOid);
            keyGenerator.Init(new KeyGenerationParameters(this.rand, keyGenerator.DefaultStrength));
            var keyGen = keyGenerator;
            KeyParameter keyParameter;
            AlgorithmIdentifier algorithmIdentifier;
            Asn1OctetString encryptedContent;
            try
            {
                byte[] key = keyGen.GenerateKey();
                keyParameter = ParameterUtilities.CreateKeyParameter(encryptionOid, key);
                Asn1Encodable asn1Parameters = this.GenerateAsn1Parameters(encryptionOid, key);
                algorithmIdentifier = this.GetAlgorithmIdentifier(encryptionOid, keyParameter, asn1Parameters, out var cipherParameters);
                IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid);
                cipher.Init(true, new ParametersWithRandom(cipherParameters, this.rand));
                MemoryStream memoryStream = new MemoryStream();
                CipherStream cipherStream = new CipherStream(memoryStream, null, cipher);
                content.Write(cipherStream);
                cipherStream.Close();
                encryptedContent = new BerOctetString(memoryStream.ToArray());
            }
            catch (Exception ex)
            {
                throw new CmsException("encrypt content failed.", ex);
            }
            Asn1EncodableVector v = new Asn1EncodableVector();
            receiverList.ForEach(s =>
            {
                try
                {
                    v.Add((Asn1Encodable)GenerateRecipientInfo(keyParameter, s.PublicKey, s.IssuerAndSerialNumber));
                }
                catch (Exception ex)
                {
                    throw new CmsException("add RecipientInfo failed", (Exception)ex);
                }
            });
            EncryptedContentInfo encryptedContentInfo = new EncryptedContentInfo(CmsObjectIdentifiers.Data, algorithmIdentifier, encryptedContent);
            Asn1Set unprotectedAttrs = null;
            if (UnprotectedAttributeGenerator != null)
                unprotectedAttrs = new BerSet(UnprotectedAttributeGenerator.GetAttributes(new Hashtable()).ToAsn1EncodableVector());
            var envelopedData = new EnvelopedData(null, new DerSet(v), encryptedContentInfo,
                unprotectedAttrs);
            var asn1Sequence = Asn1Sequence.GetInstance(envelopedData);
            Asn1EncodableVector encodableVector = new Asn1EncodableVector();
            encodableVector.Add(new DerInteger(1));
            for (var i = 1; i < asn1Sequence.Count; i++)
            {
                encodableVector.Add(asn1Sequence[i]);
            }
            var contentInfo = new ContentInfo(CmsObjectIdentifiers.EnvelopedData,
                new DerSequence(encodableVector));
            return new CmsEnvelopedData(contentInfo);
        }

        public CmsEnvelopedData AddReceiverToEnvelopedData(EncryptedContentInfo encryptedContentInfo,
            List<RecipientInfo> recipientInfos, byte[] keyBytes)
        {
            List<PublicKeyAndIssuerSerialNumber> publicKeyAndIssuerSerialNumbers = new List<PublicKeyAndIssuerSerialNumber>();
            var parser = new X509CertificateParser();
            foreach (X509Certificate2 cert in Certs)
            {
                X509Certificate certificate = parser.ReadCertificate(cert.RawData);
                publicKeyAndIssuerSerialNumbers.Add(new PublicKeyAndIssuerSerialNumber()
                {
                    PublicKey = certificate.GetPublicKey(),
                    IssuerAndSerialNumber = new IssuerAndSerialNumber(certificate.IssuerDN, certificate.SerialNumber)
                });
            }
            return AddReceiverToEnvelopedData(encryptedContentInfo, recipientInfos, keyBytes,
                publicKeyAndIssuerSerialNumbers);
        }

        public CmsEnvelopedData AddReceiverToEnvelopedData(EncryptedContentInfo encryptedContentInfo,
            List<RecipientInfo> recipientInfos, byte[] keyBytes,
            List<PublicKeyAndIssuerSerialNumber> receiverList, Asn1Set unprotectedAttrs = null)
        {
            var keyParameter =
                ParameterUtilities.CreateKeyParameter(encryptedContentInfo.ContentEncryptionAlgorithm.Algorithm.Id,
                    keyBytes);
            Asn1EncodableVector v = new Asn1EncodableVector();
            recipientInfos.ForEach(s => v.Add(s));
            receiverList.ForEach(s =>
            {
                try
                {
                    v.Add((Asn1Encodable)GenerateRecipientInfo(keyParameter, s.PublicKey, s.IssuerAndSerialNumber));
                }
                catch (Exception ex)
                {
                    throw new CmsException("add RecipientInfo failed", (Exception)ex);
                }
            });
            if (UnprotectedAttributeGenerator != null)
                unprotectedAttrs = new BerSet(UnprotectedAttributeGenerator.GetAttributes(new Hashtable()).ToAsn1EncodableVector());
            var envelopedData = new EnvelopedData(null, new DerSet(v), encryptedContentInfo,
                unprotectedAttrs);
            var asn1Sequence = Asn1Sequence.GetInstance(envelopedData);
            Asn1EncodableVector encodableVector = new Asn1EncodableVector();
            encodableVector.Add(new DerInteger(1));
            for (var i = 1; i < asn1Sequence.Count; i++)
            {
                encodableVector.Add(asn1Sequence[i]);
            }
            var contentInfo = new ContentInfo(CmsObjectIdentifiers.EnvelopedData,
                new DerSequence(encodableVector));
            return new CmsEnvelopedData(contentInfo);
        }

        public class PublicKeyAndIssuerSerialNumber
        {
            public AsymmetricKeyParameter PublicKey { get; set; }
            public IssuerAndSerialNumber IssuerAndSerialNumber { get; set; }
        }
    }
    public class SM2Cipher
    {
        private int ct;
        private ECPoint p2;
        private SM3Digest sm3keybase;
        private SM3Digest sm3c3;
        private byte[] key;
        private byte keyOff;

        public SM2Cipher()
        {
            this.ct = 1;
            this.key = new byte[32];
            this.keyOff = 0;
        }

        private void Reset()
        {
            this.sm3keybase = new SM3Digest();
            this.sm3c3 = new SM3Digest();
            byte[] p = SMToolClass.To32Bytes(p2.Normalize().XCoord.ToBigInteger());
            this.sm3keybase.BlockUpdate(p, 0, p.Length);
            this.sm3c3.BlockUpdate(p, 0, p.Length);

            p = SMToolClass.To32Bytes(p2.Normalize().YCoord.ToBigInteger());
            this.sm3keybase.BlockUpdate(p, 0, p.Length);
            this.ct = 1;
            NextKey();
        }

        private void NextKey()
        {
            SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
            sm3keycur.Update((byte)(ct >> 24 & 0xff));
            sm3keycur.Update((byte)(ct >> 16 & 0xff));
            sm3keycur.Update((byte)(ct >> 8 & 0xff));
            sm3keycur.Update((byte)(ct & 0xff));
            sm3keycur.DoFinal(key, 0);
            this.keyOff = 0;
            this.ct++;
        }

        public ECPoint Init_enc(ECPoint userKey)
        {
            ECKeyGenerationParameters ecc_ecgenparam = new ECKeyGenerationParameters(SMToolClass.ecc_bc_spec, new SecureRandom());
            ECKeyPairGenerator ecc_key_pair_generator = new ECKeyPairGenerator();
            ecc_key_pair_generator.Init(ecc_ecgenparam);
            AsymmetricCipherKeyPair key = ecc_key_pair_generator.GenerateKeyPair();
            ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)key.Private;
            ECPublicKeyParameters ecpub = (ECPublicKeyParameters)key.Public;
            BigInteger k = ecpriv.D;
            ECPoint c1 = ecpub.Q;
            this.p2 = userKey.Multiply(k);
            Reset();
            return c1;
        }

        public void Encrypt(byte[] data)
        {
            this.sm3c3.BlockUpdate(data, 0, data.Length);
            for (int i = 0; i < data.Length; i++)
            {
                if (keyOff == key.Length)
                {
                    NextKey();
                }
                data[i] ^= key[keyOff++];
            }
        }

        public void Init_dec(BigInteger userD, ECPoint c1)
        {
            this.p2 = c1.Multiply(userD);
            Reset();
        }

        public void Decrypt(byte[] data)
        {
            for (int i = 0; i < data.Length; i++)
            {
                if (keyOff == key.Length)
                {
                    NextKey();
                }
                data[i] ^= key[keyOff++];
            }

            this.sm3c3.BlockUpdate(data, 0, data.Length);
        }

        public void Dofinal(byte[] c3)
        {
            byte[] p = SMToolClass.To32Bytes(p2.Normalize().YCoord.ToBigInteger());
            this.sm3c3.BlockUpdate(p, 0, p.Length);
            this.sm3c3.DoFinal(c3, 0);
            Reset();
        }
    }

    #region SM2SignatureFactory
    public class SM2SignatureFactory : ISignatureFactory
    {
        private readonly AsymmetricKeyParameter privateKey;
        public SM2SignatureFactory(ECPrivateKeyParameters privateKey)
        {
            this.privateKey = privateKey;
        }
        public SM2SignatureFactory(byte[] privateKeyBytes)
        {
            ECPrivateKeyParameters priKeyParameters =
                new ECPrivateKeyParameters(new BigInteger(1, privateKeyBytes), SMToolClass.ecc_bc_spec);
        }

        public object AlgorithmDetails
        {
            get { return new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.156.10197.1.501")); }
        }

        public IStreamCalculator CreateCalculator()
        {
            ISigner sig = new Org.BouncyCastle.Crypto.Signers.SM2Signer();

            sig.Init(true, privateKey);

            return new SigCalculator(sig);
        }
    }
    internal class SigCalculator : IStreamCalculator
    {
        private readonly ISigner sig;
        private readonly Stream stream;

        internal SigCalculator(ISigner sig)
        {
            this.sig = sig;
            this.stream = new SignerBucket(sig);
        }

        public Stream Stream
        {
            get { return stream; }
        }

        public object GetResult()
        {
            return new SigResult(sig);
        }
    }
    internal class SignerBucket
        : Stream
    {
        protected readonly ISigner signer;

        public SignerBucket(
            ISigner signer)
        {
            this.signer = signer;
        }

        public override int Read(
            byte[] buffer,
            int offset,
            int count)
        {
            throw new NotImplementedException();
        }

        public override int ReadByte()
        {
            throw new NotImplementedException();
        }

        public override void Write(
            byte[] buffer,
            int offset,
            int count)
        {
            if (count > 0)
            {
                signer.BlockUpdate(buffer, offset, count);
            }
        }

        public override void WriteByte(
            byte b)
        {
            signer.Update(b);
        }

        public override bool CanRead
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override long Length
        {
            get { return 0; }
        }

        public override long Position
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public override void Flush()
        {
        }

        public override long Seek(
            long offset,
            SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void SetLength(
            long length)
        {
            throw new NotImplementedException();
        }
    }
    internal class SigResult : IBlockResult
    {
        private readonly ISigner sig;

        internal SigResult(ISigner sig)
        {
            this.sig = sig;
        }

        public byte[] Collect()
        {
            return sig.GenerateSignature();
        }

        public int Collect(byte[] destination, int offset)
        {
            byte[] signature = Collect();

            Array.Copy(signature, 0, destination, offset, signature.Length);

            return signature.Length;
        }
    }
    #endregion

    #region SM2VerifierFactory
    public class SM2VerifierFactoryProvider : IVerifierFactoryProvider
    {
        private readonly AsymmetricKeyParameter publicKey;

        public SM2VerifierFactoryProvider(AsymmetricKeyParameter publicKey)
        {
            this.publicKey = publicKey;
        }

        public IVerifierFactory CreateVerifierFactory(object algorithmDetails)
        {
            return new SM2VerifierFactory((AlgorithmIdentifier)algorithmDetails, this.publicKey);
        }
    }
    public class SM2VerifierFactory : IVerifierFactory
    {
        private readonly AlgorithmIdentifier algID;
        private readonly AsymmetricKeyParameter publicKey;

        public SM2VerifierFactory(string algorithm, AsymmetricKeyParameter publicKey)
        {
            this.publicKey = publicKey;
            this.algID =
                new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.156.10197.1.501"));
        }

        public SM2VerifierFactory(AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
        {
            this.publicKey = publicKey;
            this.algID = algorithm;
        }

        public object AlgorithmDetails
        {
            get
            {
                return (object)this.algID;
            }
        }

        public IStreamCalculator CreateCalculator()
        {
            ISigner sig = new Org.BouncyCastle.Crypto.Signers.SM2Signer();

            sig.Init(false, this.publicKey);

            return new VerifierCalculator(sig);
        }
    }
    internal class VerifierCalculator : IStreamCalculator
    {
        private readonly ISigner sig;
        private readonly Stream stream;

        internal VerifierCalculator(ISigner sig)
        {
            this.sig = sig;
            this.stream = (Stream)new SignerBucket(sig);
        }

        public Stream Stream
        {
            get
            {
                return this.stream;
            }
        }

        public object GetResult()
        {
            return new VerifierResult(this.sig);
        }
    }
    internal class VerifierResult : IVerifier
    {
        private readonly ISigner sig;

        internal VerifierResult(ISigner sig)
        {
            this.sig = sig;
        }

        public bool IsVerified(byte[] signature)
        {
            return this.sig.VerifySignature(signature);
        }

        public bool IsVerified(byte[] signature, int off, int length)
        {
            byte[] numArray = new byte[length];
            Array.Copy((Array)signature, 0, (Array)numArray, off, numArray.Length);
            return this.sig.VerifySignature(signature);
        }
    }
    #endregion
}